<template>
  <div class="neo4jd3">
    <map-oper
      :num="zoomTime"
      :min="25" 
      :max="300" 
      :step="25"
      :mode="showMode"
      @scalechange="changeMapZoom"
      @modechange="changeMode"
    >
    </map-oper>
    <div id="neo4jd3" v-show="showMode=='map'&&hasMapData" @click="mapClick" @contextmenu="mapRClick"></div>
    <div class="mapNone" v-show="showMode=='map'&&!hasMapData">
      <div>
        <img width="291px" height="160px" src="@/image/source-search.png" alt="">
        <p class="fontSize12 color-ash text-center">无图谱数据</p>
      </div>
    </div>
    <div class="knowledgeList" v-show="showMode=='list'">
      <div v-show="hasListData">
        <knowledge-list
          :data="listData"
          v-show="hasListData"
        >
        </knowledge-list>
      </div>
      <div class="listNone" v-show="!hasListData">
        <div>
          <img width="291px" height="160px" src="@/image/source-search.png" alt="">
          <p class="fontSize12 color-ash text-center">无路径数据</p>
        </div>
      </div>
    </div>
    <el-dropdown trigger="click" class="listBg" ref="nodeListBg" @command="nodeListClick">
      <span class="listContent" ref="nodeListContent"></span>
      <el-dropdown-menu slot="dropdown" ref="nodeList">
        <el-dropdown-item :command='"edit"' v-if="operatype=='默认'">编辑节点</el-dropdown-item>
        <el-dropdown-item :command='"delete"' v-if="operatype=='默认'">删除节点</el-dropdown-item>
        <el-dropdown-item :command='"near"'>查看临近节点</el-dropdown-item>
      </el-dropdown-menu>
    </el-dropdown>
    <el-dropdown trigger="click" class="listBg" ref="shipListBg" @command="shipListClick">
      <span class="listContent" ref="shipListContent"></span>
      <el-dropdown-menu slot="dropdown" ref="shipList">
        <el-dropdown-item :command='"delete"'>删除关系</el-dropdown-item>
      </el-dropdown-menu>
    </el-dropdown>
  </div>
</template>

<script>
import mapOper from './components/mapOper.vue'
import knowledgeList from '@/components/knowledgeNodeList'
import rootNode from './js/rootNode.json'
import childNode from './js/childNode.json'
import pathData from './js/path.json'
import Neo4jd3 from './js/neo4jd3.js'
import * as d3 from './js/d3.min.js'

export default {
  name: 'neo4j-d3',
  props: {
    operatable: {
      type: Boolean,
      default: true
    },
    operatype: {
      type: String,
      default: '默认'
    },
    showallpath: {
      type: Boolean,
      default: false
    },
    querydata: {
      type: Object,
      default: function(){
        return {};
      }
    }
  },
  components: {
    mapOper,
    knowledgeList
  },
  data () {
    return {
      // d3Loaded: false,
      // neo4jLoaded: false,
      mapEL: null,
      zoomTime: 100,
      shipDataFromClick: null,
      nodeDataFromClick: null,
      showMode: 'map',
      mapData: null,
      loadMapTimer: null,
      emptyMapData: {
        "results": [
          {
            "columns": ["user","entity"],
            "data": [
              {
              "graph": {
                  "nodes": [],
                  "relationships": []
                }
              }
            ]
          }
        ]
      },
      listData: [],
    }
  },
  computed: {
    // scriptsLoaded(){
    //   return this.d3Loaded && this.neo4jLoaded;
    // },
    hasMapData(){
      if(!this.mapData){
        return false;
      }
      try {
        var len = this.mapData.results[0].data[0].graph.nodes.length
        if(len>0){
          return true
        } else {
          return false
        }
      } catch (error) {
        return false;
      }
    },
    hasListData(){
      if(!this.listData){
        return false;
      }
      return true;
    },
  },
  watch: {
    // scriptsLoaded(val){
    //   if(val===true){
    //     this.loadMap();
    //   }
    // },
    showMode(){
      this.initMap();
    }
  },
  mounted () {
    this.$nextTick(()=>{
      document.body.appendChild(this.$refs['nodeListBg'].$el)
      document.body.appendChild(this.$refs['shipListBg'].$el)
      this.loadMap();
    })
  },
  beforeDestroy(){
    document.body.removeChild(this.$refs['nodeListBg'].$el)
    document.body.removeChild(this.$refs['shipListBg'].$el)
  },
  methods: {
    loadMap() {
      clearTimeout(this.loadMapTimer);
      this.loadMapTimer = setTimeout(()=>{
        rootNode.results[0].data[0].graph.nodes.forEach(item => {
          item.nodeType = item.labels;
          item.labels = [item.properties.name];
        });
        this.mapData = rootNode;
        this.initMap();
        this.listData = pathData;
      },300)
    },
    loadNearNodes(node){
      var near = childNode[node.id];
      if(!near||!near.nodes||near.nodes.length<1){
        this.$message({
          type: 'info',
          message: '没有临近节点数据'
        })
        return;
      }
      this.mapData = this.mergeNode(near)
      this.mapEL.loadNeo4jData(this.mapData)
      // 通过模拟拖拽来更新节点链接状态
      this.mapEL.modeDragStarted(this.nodeDataFromClick);
      setTimeout(()=>{
        this.mapEL.modDragged(this.nodeDataFromClick);
      },100)
      setTimeout(()=>{
        this.mapEL.modDragEnded(this.nodeDataFromClick);
      },200)
    },
    // 合并节点数据
    mergeNode(data){
      var oldData = JSON.parse(JSON.stringify(this.mapData));
      data.nodes.forEach(item => {
        item.nodeType = item.labels;
        item.labels = [item.properties.name];
      });
      oldData.results[0].data[0].graph.nodes = oldData.results[0].data[0].graph.nodes.concat(data.nodes)
      oldData.results[0].data[0].graph.relationships = oldData.results[0].data[0].graph.relationships.concat(data.relationships)
      // 数据去重
      this.duplicateRemovalFromId(oldData.results[0].data[0].graph.nodes);
      this.duplicateRemovalFromId(oldData.results[0].data[0].graph.relationships);
      return oldData;
    },
    // 数据去重
    duplicateRemovalFromId(arr){
      for(var i=arr.length-1;i>-1;i--){
        if(arr.filter(item=>item.id==arr[i].id).length>1){
          arr.splice(i,1)
        }
      }
    },
    mapClick(e) {
      if(!this.operatable) {
        return;
      }
      this.hideList('node');
      this.hideList('ship');
    },
    mapRClick(e) {
      if(!this.operatable) {
        return;
      }
      if(this.isClickRelationship(e)){
        if(this.operatype=='游客'){
          return;
        }
        this.hideList('node');
        this.showList('ship',e);
        return;
      }
      if(this.isClickNode(e)){
        this.hideList('ship');
        this.showList('node',e);
        return;
      }
      this.shipDataFromClick = null;
      this.nodeDataFromClick = null;
      this.hideList('node');
      this.hideList('ship');
    },
    showList(type,e) {
      var listBg = this.$refs[type+'ListBg'].$el;
      var listContent = this.$refs[type+'ListContent'];
      var list = this.$refs[type+'List'].$el;
      var left = e.clientX;
      var top = e.clientY;
      listBg.style.left = left+'px';
      listBg.style.top = top+'px';
      if(list.style.display=='none'){
        listContent.click();
      }else{
        listContent.click();
        setTimeout(()=>{
          listContent.click();
        },100)
      }
    },
    hideList(type){
      var listContent = this.$refs[type+'ListContent'];
      var list = this.$refs[type+'List'].$el;
      if(list.style.display!='none'){
        listContent.click();
      }
    },
    isClickRelationship(e){
      var path = e.path;
      for(var i=0;i<path.length;i++){
        var cList = path[i].classList;
        if(cList&&cList.length>0&&cList[0]=='relationship'){
          return true;
        }
      }
      return false;
    },
    isClickNode(e){
      var path = e.path;
      for(var i=0;i<path.length;i++){
        var cList = path[i].classList;
        if(cList&&cList.length>0&&cList[0]=='node'){
          return true;
        }
      }
      return false;
    },
    nodeListClick(val){
      this.$emit('nodeRMenuCLick',val,this.nodeDataFromClick)
      if (val == 'near'){
        this.loadNearNodes(this.nodeDataFromClick);
      }
    },
    shipListClick(val){
      this.$emit('shipRMenuCLick',val,this.shipDataFromClick)
    },
    initMap() {
      if (this.showMode == 'map') {
        try {
          this.mapData.results[0].data[0].graph.nodes.forEach(item=>{
            delete item.fy;
            delete item.fx;
          })
        } catch (error) {
          
        }
        this.initNeo4jd3(this.mapData);
      }
    },
    initNeo4jd3(data,zoom){
      var that = this;
      this.zoomTime = zoom||100;
      this.mapEL = new Neo4jd3('#neo4jd3', {
          highlight: [
            {
              class: 'Project',
              property: 'name',
              value: 'neo4jd3'
            }, {
              class: 'User',
              property: 'userId',
              value: 'eisman'
            }
          ],
          minCollision: 60,
          neo4jData: data,
          nodeRadius: 32,
          minScale: 0.25,
          maxScale: 3,
          scaleStep: 0.25,
          onNodeClick: function(d) {
            that.$emit('nodeCLick',d)
            console.log('节点点击',d)
          },
          onNodeRClick: function(d) {
            that.nodeDataFromClick = d;
          },
          onNodeDoubleClick: function(d) {
            console.log('节点双击',d)
            
          },
          onRelationshipClick: function(d) {
            that.$emit('shipCLick',d)
          },
          onRelationshipRClick: function(d) {
            that.shipDataFromClick = d;
          },
          onRelationshipDoubleClick: function(d) {
            console.log('关系双击',d);
          },
          onWheelZoom: function(scale) {
            that.zoomTime = parseInt(scale*100)
          },
          zoomFit: false
      }, d3);
      setTimeout(()=>{
        this.changeMapZoom(zoom||100);
      },100)
    },
    changeMapZoom(val){
      if(!this.mapEL){
        return
      }
      if(!val){
        this.zoomTime = 100
      }
      this.zoomTime = val;
      this.mapEL.zoomFit(this.zoomTime/100)
    },
    changeMode(val){
      this.showMode = val;
    },
    // loadScripts(){
    //   if(!window.d3){
    //     this.loadScript(process.env.BASE_URL+'d3.min.js',()=>{
    //       this.d3Loaded = true;
    //       if(!window.Neo4jd3){
    //         this.loadScript(process.env.BASE_URL+'neo4jd3.js',()=>{
    //           this.neo4jLoaded = true;
    //         })
    //       }else{
    //         this.neo4jLoaded = true;
    //       }
    //     })
    //   }else{
    //     this.d3Loaded = true;
    //     if(!window.Neo4jd3){
    //       this.loadScript(process.env.BASE_URL+'neo4jd3.js',()=>{
    //         this.neo4jLoaded = true;
    //       })
    //     }else{
    //       this.neo4jLoaded = true;
    //     }
    //   }
    // },
    // loadScript(src, callback) {
    //   var script = document.createElement('script'),
    //   head = document.getElementsByTagName('head')[0];
    //   script.type = 'text/javascript';
    //   script.src = src;
    //   if (script.addEventListener) {
    //     script.addEventListener('load', function () {
    //       callback();
    //     }, false);
    //   } else if (script.attachEvent) {
    //     script.attachEvent('onreadystatechange', function () {
    //       var target = window.event.srcElement;
    //       if (target.readyState == 'loaded') {
    //         callback();
    //       }
    //     });
    //   }
    //   head.appendChild(script);
    // }
  }
}
</script>

<style lang='scss' scoped>
@import "./css/neo4jd3.css";
.neo4jd3 {
  height: 100%;
  display: flex;
  flex-direction: column;
  background-color: $background-default;
  #neo4jd3 {
    flex: 1;
  }
  .knowledgeList {
    height: 100%;
    .title {
      padding: 20px 0 10px 30px;
      font-size: $font-size16;
      color: $color-222;
      font-weight: bold;
    }
    .knowledgeListBg{
      padding-top: 10px;
    }
  }
  .listNone,
  .mapNone {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}

.listBg {
  position: absolute;
  top:0;
  left:0;
  width:1px;
  height:1px;
}

</style>
